package observer

import (
	"sync"
	"sync/atomic"
	"time"
)

type tMockTimeService struct {
	observers map[string]ITimeObserver
	rwmutex *sync.RWMutex
	speed int64
	state int64
}

func NewMockTimeService(speed int64) ITimeService {
	it := &tMockTimeService{
		observers: make(map[string]ITimeObserver, 0),
		rwmutex: new(sync.RWMutex),
		speed: speed,
		state: 0,
	}
	it.Start()
	return it
}

func (me *tMockTimeService) Start() {
	if !atomic.CompareAndSwapInt64(&(me.state), 0, 1) {
		return
	}

	go func() {
		timeFrom := time.Now()
		timeOffset := timeFrom.UnixNano()

		for range time.Tick(time.Duration(100)*time.Millisecond) {
			if me.state == 0 {
				break
			}

			nanos := (time.Now().UnixNano() - timeOffset) * me.speed
			t := timeFrom.Add(time.Duration(nanos) * time.Nanosecond)

			me.NotifyAll(&t)
		}
	}()
}


func (me *tMockTimeService) NotifyAll(now *time.Time) {
	me.rwmutex.RLock()
	defer me.rwmutex.RUnlock()

	for _,it := range me.observers {
		go it.TimeElapsed(now)
	}
}


func (me *tMockTimeService) Attach(it ITimeObserver) {
	me.rwmutex.Lock()
	defer me.rwmutex.Unlock()

	me.observers[it.ID()] = it
}


func (me *tMockTimeService) Detach(id string) {
	me.rwmutex.Lock()
	defer me.rwmutex.Unlock()

	delete(me.observers, id)
}

var GlobalTimeService = NewMockTimeService(1800)